; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=riscv32 -mattr=+d -target-abi=ilp32 -verify-machineinstrs < %s \
; RUN:   | FileCheck -check-prefix=RV32IFD %s

; Basic correctness checks for calling convention lowering for RV32D. This can
; be somewhat error-prone for soft-float RV32D due to the fact that f64 is legal
; but i64 is not, and there is no instruction to move values directly between
; the GPRs and 64-bit FPRs.

define double @callee_double_inreg(double %a, double %b) nounwind {
; RV32IFD-LABEL: callee_double_inreg:
; RV32IFD:       # %bb.0:
; RV32IFD-NEXT:    addi sp, sp, -16
; RV32IFD-NEXT:    sw a2, 8(sp)
; RV32IFD-NEXT:    sw a3, 12(sp)
; RV32IFD-NEXT:    fld fa5, 8(sp)
; RV32IFD-NEXT:    sw a0, 8(sp)
; RV32IFD-NEXT:    sw a1, 12(sp)
; RV32IFD-NEXT:    fld fa4, 8(sp)
; RV32IFD-NEXT:    fadd.d fa5, fa4, fa5
; RV32IFD-NEXT:    fsd fa5, 8(sp)
; RV32IFD-NEXT:    lw a0, 8(sp)
; RV32IFD-NEXT:    lw a1, 12(sp)
; RV32IFD-NEXT:    addi sp, sp, 16
; RV32IFD-NEXT:    ret
  %1 = fadd double %a, %b
  ret double %1
}

; TODO: code quality for loading and then passing f64 constants is poor.

define double @caller_double_inreg() nounwind {
; RV32IFD-LABEL: caller_double_inreg:
; RV32IFD:       # %bb.0:
; RV32IFD-NEXT:    addi sp, sp, -16
; RV32IFD-NEXT:    sw ra, 12(sp) # 4-byte Folded Spill
; RV32IFD-NEXT:    lui a0, 262236
; RV32IFD-NEXT:    addi a1, a0, 655
; RV32IFD-NEXT:    lui a0, 377487
; RV32IFD-NEXT:    addi a0, a0, 1475
; RV32IFD-NEXT:    lui a2, 262364
; RV32IFD-NEXT:    addi a3, a2, 655
; RV32IFD-NEXT:    mv a2, a0
; RV32IFD-NEXT:    call callee_double_inreg@plt
; RV32IFD-NEXT:    lw ra, 12(sp) # 4-byte Folded Reload
; RV32IFD-NEXT:    addi sp, sp, 16
; RV32IFD-NEXT:    ret
  %1 = call double @callee_double_inreg(double 2.720000e+00, double 3.720000e+00)
  ret double %1
}

define double @callee_double_split_reg_stack(i32 %a, i64 %b, i64 %c, double %d, double %e) nounwind {
; RV32IFD-LABEL: callee_double_split_reg_stack:
; RV32IFD:       # %bb.0:
; RV32IFD-NEXT:    addi sp, sp, -16
; RV32IFD-NEXT:    lw a0, 16(sp)
; RV32IFD-NEXT:    sw a7, 8(sp)
; RV32IFD-NEXT:    sw a0, 12(sp)
; RV32IFD-NEXT:    fld fa5, 8(sp)
; RV32IFD-NEXT:    sw a5, 8(sp)
; RV32IFD-NEXT:    sw a6, 12(sp)
; RV32IFD-NEXT:    fld fa4, 8(sp)
; RV32IFD-NEXT:    fadd.d fa5, fa4, fa5
; RV32IFD-NEXT:    fsd fa5, 8(sp)
; RV32IFD-NEXT:    lw a0, 8(sp)
; RV32IFD-NEXT:    lw a1, 12(sp)
; RV32IFD-NEXT:    addi sp, sp, 16
; RV32IFD-NEXT:    ret
  %1 = fadd double %d, %e
  ret double %1
}

define double @caller_double_split_reg_stack() nounwind {
; RV32IFD-LABEL: caller_double_split_reg_stack:
; RV32IFD:       # %bb.0:
; RV32IFD-NEXT:    addi sp, sp, -16
; RV32IFD-NEXT:    sw ra, 12(sp) # 4-byte Folded Spill
; RV32IFD-NEXT:    lui a0, 262510
; RV32IFD-NEXT:    addi a2, a0, 327
; RV32IFD-NEXT:    lui a0, 262446
; RV32IFD-NEXT:    addi a6, a0, 327
; RV32IFD-NEXT:    lui a0, 713032
; RV32IFD-NEXT:    addi a5, a0, -1311
; RV32IFD-NEXT:    li a0, 1
; RV32IFD-NEXT:    li a1, 2
; RV32IFD-NEXT:    li a3, 3
; RV32IFD-NEXT:    sw a2, 0(sp)
; RV32IFD-NEXT:    li a2, 0
; RV32IFD-NEXT:    li a4, 0
; RV32IFD-NEXT:    mv a7, a5
; RV32IFD-NEXT:    call callee_double_split_reg_stack@plt
; RV32IFD-NEXT:    lw ra, 12(sp) # 4-byte Folded Reload
; RV32IFD-NEXT:    addi sp, sp, 16
; RV32IFD-NEXT:    ret
  %1 = call double @callee_double_split_reg_stack(i32 1, i64 2, i64 3, double 4.72, double 5.72)
  ret double %1
}

define double @callee_double_stack(i64 %a, i64 %b, i64 %c, i64 %d, double %e, double %f) nounwind {
; RV32IFD-LABEL: callee_double_stack:
; RV32IFD:       # %bb.0:
; RV32IFD-NEXT:    addi sp, sp, -16
; RV32IFD-NEXT:    fld fa5, 24(sp)
; RV32IFD-NEXT:    fld fa4, 16(sp)
; RV32IFD-NEXT:    fadd.d fa5, fa4, fa5
; RV32IFD-NEXT:    fsd fa5, 8(sp)
; RV32IFD-NEXT:    lw a0, 8(sp)
; RV32IFD-NEXT:    lw a1, 12(sp)
; RV32IFD-NEXT:    addi sp, sp, 16
; RV32IFD-NEXT:    ret
  %1 = fadd double %e, %f
  ret double %1
}

define double @caller_double_stack() nounwind {
; RV32IFD-LABEL: caller_double_stack:
; RV32IFD:       # %bb.0:
; RV32IFD-NEXT:    addi sp, sp, -32
; RV32IFD-NEXT:    sw ra, 28(sp) # 4-byte Folded Spill
; RV32IFD-NEXT:    lui a0, 262510
; RV32IFD-NEXT:    addi a0, a0, 327
; RV32IFD-NEXT:    sw a0, 4(sp)
; RV32IFD-NEXT:    lui a0, 713032
; RV32IFD-NEXT:    addi a1, a0, -1311
; RV32IFD-NEXT:    sw a1, 0(sp)
; RV32IFD-NEXT:    lui a0, 262574
; RV32IFD-NEXT:    addi a0, a0, 327
; RV32IFD-NEXT:    sw a0, 12(sp)
; RV32IFD-NEXT:    li a0, 1
; RV32IFD-NEXT:    li a2, 2
; RV32IFD-NEXT:    li a4, 3
; RV32IFD-NEXT:    li a6, 4
; RV32IFD-NEXT:    sw a1, 8(sp)
; RV32IFD-NEXT:    li a1, 0
; RV32IFD-NEXT:    li a3, 0
; RV32IFD-NEXT:    li a5, 0
; RV32IFD-NEXT:    li a7, 0
; RV32IFD-NEXT:    call callee_double_stack@plt
; RV32IFD-NEXT:    lw ra, 28(sp) # 4-byte Folded Reload
; RV32IFD-NEXT:    addi sp, sp, 32
; RV32IFD-NEXT:    ret
  %1 = call double @callee_double_stack(i64 1, i64 2, i64 3, i64 4, double 5.72, double 6.72)
  ret double %1
}

define double @func_return_double_undef() nounwind {
; RV32IFD-LABEL: func_return_double_undef:
; RV32IFD:       # %bb.0:
; RV32IFD-NEXT:    ret
  ret double undef
}
